<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script>
    /*
    * 统计字符串：
    *   "chwenkoewvbjbqpifdhqiekncdvgiwefjdviernvenvcf"
    *   得出一个对象{
    *       a:3,
    *       b:5,
    *       c:8,
    *       e:5
    *   }
    *   推荐：reduce数组的方法
    * */

    let str = "chwenkoewvbjbqpifdhqiekncdvgiwefjdviernvenvcf"

    function getResult(str){
        let result = {}//存放统计结果的对象
        //字符串转换成数组
        let arr = str.split("")//空字符串就是以这个空隙为间隔 每个都形成独立的元素 如果不加参数就会直接整个str变成一个数组
        //接下来的需求是要做统计 统计的结果是对象  假设迭代的数组a是["a","b","a"]
        arr.reduce(function (total,item,index,arr){ //回调函数可接收的四个形参
            // a数组第一次迭代，total的初始值是空对象{}，item是字符串"a"；
            // 第二次进行迭代，total值变成了刚刚返回出来的迭代结果{a:1},item值为下一项"b"，
            // 第三次进行迭代，total值变成了刚刚返回出来的迭代结果{a:1,b:1}，item值为下一项"a"
            //先判断total里面的item属性是否存在 存在就统计个数 不存在就给该属性添加个初始值1
            if(total[item]){//这里涉及到隐式类型转换 如果属性存在，长度就大于0，转化为布尔值就是true 表示如果该属性存在（这些属性就是其中的每个字母 一开始统计结果的初始值就是空对象 是没有任何属性的）
                total[item]++ //接上面第三次迭代内容 对象{a:1,b:1}访问字符串"a"属性是否存在，存在，a属性对应值加1，变成{a:2,b:1}
            }else{
                total[item] = 1 //如果没有该属性，就初始化该属性并赋值为1 接上面第一次迭代内容空对象{}访问字符串"a"属性是否存在，不存在，就将a属性初始值为1，变成{a:1}
                                //接上面第二次迭代内容 对象{a:1}访问字符串"b"属性是否存在，不存在，就将b属性初始值为1，变成{a:1,b:1}
            }
            return total //回调函数的返回值 迭代结果 作为下次迭代的迭代体 接上面第一次迭代：将迭代结果{a:1}返回出去，再次进行迭代；
                         //接上面第二次迭代，将迭代结果{a:1,b:1}返回出去，再次进行下次迭代
                         //接上面第三次迭代，将迭代结果{a:2,b:1}返回出去，迭代完成
        },result)//将一开始的对象作为迭代体初始值传入
        return result
    }

    let s1 = getResult(str)
    console.log(s1);

    //和上面的方法思想一致
    const getResult2 = str => str.split("").reduce((x,y) => ((x[y]?x[y]++:x[y]=1),x),{})
    //const getResult2是一部分，后面箭头函数str => str.split("").reduce((x,y) => ((x[y]?x[y]++:x[y]=1),x),{})是另一部分，详细解析在下方
    //即声明常量，为其赋值箭头函数内容，为什么用常量声明，一般声明的函数都不喜欢进行就跟，就用常量
    function f(str){ //这个函数等价于上方箭头函数
        return str.split("").reduce((x,y) => ((x[y]?x[y]++:x[y]=1),x),{})
    }

    //str => str.split("")//将字符串str拆开拼接成一个数组，返回该数组
    //上面返回了一个数组，这里继续对那个返回的数组进行操作.reduce((x,y) =>
    //((x[y]?x[y]++:x[y]=1),x //注意这里的逗号,逗号运算符，逗号前面的计算完，返回逗号后面的内容 x),{})
    //x是回调函数接收的参数迭代体 y回调函数接收的参数每一个字符 reduce迭代体初始值为空对象

</script>
</body>
</html>